﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using ICSharpCode.SharpZipLib.Core;
using ICSharpCode.SharpZipLib.Zip;
using Spring.Data;
using Spring.Data.Common;
using Spring.Data.Core;
using Common.Logging;
using System.Text.RegularExpressions;

namespace CMS6Tools.Common.Utility
{
    public static class FileSystemUtility
    {
        public static void CopyDirectory(string sourcePath, string destinationPath, bool recursive = true, ILog Logger = null, string excludedFolderPattern = null)
        {
            Logger = Logger ?? new global::Common.Logging.Simple.NoOpLogger();
            excludedFolderPattern = excludedFolderPattern ?? "";
            var needCheckPattern = !string.IsNullOrEmpty(excludedFolderPattern);

            var subFiles = Directory.GetFiles(sourcePath);
            foreach (var subFile in subFiles)
            {
                var destSubFile = Path.Combine(destinationPath, Path.GetFileName(subFile));
                File.Copy(subFile, destSubFile);
                var fileInfo = new FileInfo(destSubFile);
                fileInfo.IsReadOnly = false;
                Logger.Info(string.Format("Copied file:{0}.", subFile));
            }

            var subDirectories = Directory.GetDirectories(sourcePath);
            foreach (var subDirectory in subDirectories)
            {
                if (needCheckPattern && Regex.IsMatch(subDirectory, excludedFolderPattern))
                {
                    Logger.Info(string.Format("Ignored Folder:{0}.", subDirectory));
                    continue;
                }

                var destSubDirectory = Path.Combine(destinationPath, Path.GetFileName(subDirectory));
                Directory.CreateDirectory(destSubDirectory);

                CopyDirectory(subDirectory, destSubDirectory, Logger: Logger, excludedFolderPattern:excludedFolderPattern);
            }
        }

        public static string Combine(params string[] paths)
        {
            return Path.Combine(paths).Replace('/', '\\');
        }

        public static void CopyFolder(string sourceFolderPath, string targetFolderPath, bool overwrite = true)
        {
            if (string.IsNullOrEmpty(sourceFolderPath) || string.IsNullOrEmpty(targetFolderPath))
                return;

            if (!Directory.Exists(sourceFolderPath))
                return;

            if (!Directory.Exists(targetFolderPath))
                Directory.CreateDirectory(targetFolderPath);

            foreach (var entry in Directory.GetFileSystemEntries(sourceFolderPath))
            {
                var targetEntry = Combine(targetFolderPath, Path.GetFileName(entry));
                if (Directory.Exists(entry))
                {
                    CopyFolder(entry, targetEntry, overwrite);
                }
                else
                {
                    File.Copy(entry, targetEntry, overwrite);
                }
            }
        }

        public static void DeleteFolder(string folderPath, bool recursive, params string[] excludedFileEntryNames)
        {
            if (string.IsNullOrEmpty(folderPath) || !Directory.Exists(folderPath))
                return;

            excludedFileEntryNames = excludedFileEntryNames.Where(c => !string.IsNullOrEmpty(c)).ToArray();

            if (!excludedFileEntryNames.Any())
            {
                Directory.Delete(folderPath, recursive);
            }
            else
            {
                ClearSubFolders(folderPath, recursive, excludedFileEntryNames);

                if (!Directory.GetFileSystemEntries(folderPath).Any() && !excludedFileEntryNames.Any(c => c.Equals(folderPath, StringComparison.InvariantCultureIgnoreCase)))
                    Directory.Delete(folderPath);
            }
        }

        public static void ClearSubFolders(string folderPath, bool recursive, params string[] excludedFileEntryNames)
        {
            if (string.IsNullOrEmpty(folderPath) || !Directory.Exists(folderPath))
                return;

            foreach (var entry in Directory.GetFileSystemEntries(folderPath))
            {
                if (excludedFileEntryNames.Any(c => entry.Equals(c, StringComparison.InvariantCultureIgnoreCase)))
                    excludedFileEntryNames = excludedFileEntryNames.Where(c => !entry.Equals(c, StringComparison.InvariantCultureIgnoreCase)).ToArray();
                else
                {
                    // File
                    if (!Directory.Exists(entry))
                    {
                        File.Delete(entry);
                    }
                    // Folder
                    else
                    {
                        DeleteFolder(entry, recursive, excludedFileEntryNames);
                    }
                }
            }
        }
    }
}